'''
Created on Jan 29, 2010

@author: Andrzej
'''

import time
import re
import os
from Interface import SerialInterface, TelnetInterface, SimInterface
from PyDaq.Utils.Debug import dbg

PROMPT_FOUND     = 1
PROMPT_NOT_FOUND = 0
PORT_OPEN        = 1
PORT_CLOSED      = 0
PORT_ERROR       = -1

INTERFACE_SIM    = 0
INTERFACE_COM    = 1
INTERFACE_TELNET = 2

TIMEOUT          = 2

_ip_addr    = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
_win_serial = re.compile('COM') 
class AvrShell:
    """
    The AvrShell interface object
    """
       
    debug = 3
    interface_type = INTERFACE_SIM
    
    def __init__(self, address):
        dbg(self, 1, "__init__(self, address)")
        interface_details = DetermineInterfaceType(address)
        interface_type    = interface_details[0]
     
        if interface_type == INTERFACE_COM:
            try:
                self.Interface = SerialInterface(port=interface_details[1]);
                self.open()
            except:
                dbg(self, 1, "EXCEPTION during SerialInterface initialization")
                
        elif interface_type == INTERFACE_TELNET:
            try:
                self.Interface = TelnetInterface(host=interface_details[1][0],port=interface_details[1][1]);
                self.open()
            except:
                dbg(self, 1, "EXCEPTION during TelnetInterface initialization")
        else:
            self.Interface = SimInterface(port=interface_details[1])

    def  __unicode__(self):
        msg = 'AvrShell'
        return msg
        
    def __del__(self):        
        try:
            #dbg(self, 2, "def __del__(self):")
            #self.close()
            pass
        except:
            print "EXCEPTION IN: AvrShell.__del__(self):"

    def open(self):
        dbg(self, 2, "def open(self):")
        try:
            self.Interface.open()
        except:
            dbg(self, 1, "EXCEPTION IN: AvrShell.open(self):")

    def close(self):
        dbg(self, 2, "def close(self):")
        try:
            self.Interface.close()        
            return self.Interface.isOpen()
        except:
            dbg(self, 1, "EXCEPTION IN: AvrShell.close(self):")
            return -1
    
    def send(self, cmd):
        msg = 'def send(self, cmd="%s"):' % cmd
        dbg(self, 2, msg)
        try:
            self.Interface.send(cmd)
            return 0
        except:
            dbg(self, 1, "EXCEPTION IN: AvrShell.send(self, cmd):")
            return 1
    
    def query(self, cmd, expected_text='', tag='',delay=0):
        dbg(self, 2, "def query(self,cmd=%s):" % cmd)
        if tag:
            expected_text = '</' + tag + '>'
        if self.prompt():
            self.send(cmd)
            time.sleep(delay)
            out   = self.read(expected_text)
            if tag:
                pattern = re.compile(r'(?:<{0}>)(.*)(?:</{0}>)'.format(tag), re.DOTALL)
                temp = pattern.findall(out)
                if len(temp)>0:
                    out = temp[0]
                else:
                    out = ''
            return (0, out)
        else:
            dbg(self, 1, "EXCEPTION IN: AvrShell.query(self, cmd, expected_text='', tag='',delay=0):")
            return (1, '')
                   
    def read(self,expected_text=''):
        #dbg(self, 2, "def read(self):")
        try:
            response = self.Interface.read(expected_text)
            #dbg(self, 3, "Response: " + response)
        except:
            dbg(self, 1, "EXCEPTION IN: AvrShell.read(self,expected_text=''):")
            response = ''
        return response
    
    def prompt(self,attempt=1):
        
        max_attempt = 3
        try:
            prompt = self.Interface.GetPrompt()        
            if prompt == PROMPT_FOUND:
                return True
            elif prompt == PORT_ERROR:
                self.Interface.close()
                time.sleep(0.5)
                self.Interface.open()
                if attempt > max_attempt:
                    return False
                else:
                    attempt+=1
                    self.prompt(attempt)
            else:
                if attempt > max_attempt:
                    return False
                else:
                    attempt+=1
                    self.prompt(attempt)
        except:
            dbg(self, 1, "EXCEPTION IN: AvrShell.prompt(self,attempt=1):")

def DetermineInterfaceType(address):
    """
        Attempt to determine if the address is COM or Telnet and the operating system
    """
    com_expr = re.compile("(?:^COM)(\d+)")
    ip_expr  = re.compile('(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:\s+)(\d+)')
    tty_expr = re.compile("(?:/dev/)(tty\w+)")
    
    interface_type = INTERFACE_SIM
    address_out    = 0
    debug = 0
    if debug:
        print "def DetermineInterfaceType(address):" 
    if type(address) is int:
        if debug:
            print "\taddress is an integer"
        interface_type = INTERFACE_COM
        address_out    = address
    elif type(address) is str:
        if debug:
            print "\taddress is a a string"
        result = com_expr.findall(address)
        if len(result) > 0:
            if debug:
                print "\tThe address is COM port on NT os"
            interface_type = INTERFACE_COM
            address_out    = int(result[0])        
        
        result = tty_expr.findall(address)
        if len(result) > 0:
            if debug:
                print "\tThe address is tty port on Unix os"
            interface_type = INTERFACE_COM
            address_out    = result[0]
            
        result = ip_expr.findall(address)
        if len(result):
            if debug:
                print "\tThe address is IP via telnet"
            interface_type = INTERFACE_TELNET
            address_out    = (result[0][0],int(result[0][1]))
    else:
        if debug:
            print "\taddress type is not supported"    
    return (interface_type, address_out)
    
if __name__ == '__main__':
    print "\n================================================================"
    print "AvrShell module test function"
    
    DetermineInterfaceType_test = 0
    telnet_test                 = 1
    com_port_test               = 0
    sim_port_test               = 0
    test4                       = 0
    
    if DetermineInterfaceType_test:
        print "\n================================================================"
        print "\tDetermineInterfaceType_test"
        out = DetermineInterfaceType("COM8")    
        out = DetermineInterfaceType("/dev/ttyUSB0")    
        out = DetermineInterfaceType(8)    
        out = DetermineInterfaceType("192.168.1.101 2000")    
        out = DetermineInterfaceType((6,'as'))    
    if telnet_test:
        print "\n================================================================"
        print "\ttelnet_test"
        A = AvrShell('192.168.1.101 2000')    
        print A.query("I", expected_text="</idn>", tag="idn")
        A.close()
        del(A)
    if com_port_test:
        print "\n================================================================"
        print "com_port_test\n"
        A = AvrShell(7)
        print A.query("idn", expected_text="cmd")
        A.close()
        del(A)
    if sim_port_test:
        print "\n================================================================"
        print "\tsim_port_test"
        A = AvrShell('sim')    
        print A.query("I", expected_text="cmd")
        A.close()
        del(A)
    if test4:
        print "\n================================================================"
        print "\tTEST3"
    
    print "\nAll done"
    print "================================================================"